﻿using System;
using System.ComponentModel;
using System.Globalization;

namespace Jerkymon
{
    /// <summary>
    /// From URL : http://www.codeproject.com/KB/string/stringconversion.aspx
    /// Sample below
    /// bool b      = "true".ConvertTo<bool>();
    /// DateTime d1 = " 01:23:45 ".ConvertTo<DateTime>();
    /// Point p     = "100,25".ConvertTo<Point>();
    /// //convert, but use specific culture. 
    /// //in this case the comma is used as a decimal seperator
    /// Double d    = "1.234,567".ConvertTo<double>("NL")
    /// //provide a default value, if conversion fails
    /// Guid g      = "i'm not a guid".ConvertTo<Guid>(Guid.Empty);
    ///</summary>
    public static class StringExtensions
    {
		#region Static Methods (9)
		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. 
        /// If the conversion fails an exception will be raised. Supply a default value to suppress the exception.
        /// </summary>
        public static T ConvertTo<T>(this string value)
        {
            return ConvertTo<T>(value, CultureInfo.InvariantCulture);
        }

		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. 
        /// If the conversion fails the <param name="defaultValue">default value</param> will be returned.
        /// </summary>
        public static T ConvertTo<T>(this string value, T defaultValue)
        {
            return ConvertTo<T>(value, CultureInfo.InvariantCulture, defaultValue);
        }

		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. 
        /// If the conversion fails an exception will be raised. Supply a default value to suppress the exception.
        /// </summary>
        public static T ConvertTo<T>(this string value, string culture)
        {
            return ConvertTo<T>(value, CultureInfo.GetCultureInfo(culture));
        }

		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. 
        /// If the conversion fails an exception will be raised. Supply a default value to suppress the exception.
        /// </summary>
        /// <typeparam name="T">The type to return</typeparam>
        /// <param name="value">The value.</param>
        /// <param name="culture">The culture.</param>
        /// <returns></returns>
        public static T ConvertTo<T>(this string value, CultureInfo culture)
        {
            //return ConvertTo<T>(value, culture, default(T), true);

            // always hide exceptions
            return ConvertTo<T>(value, culture, default(T), false);
        }

		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. 
        /// If the conversion fails the <param name="defaultValue">default value</param> will be returned.
        /// </summary>
        public static T ConvertTo<T>(this string value, string culture, T defaultValue)
        {
            return ConvertTo<T>(value, CultureInfo.GetCultureInfo(culture), defaultValue);
        }

		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. 
        /// If the conversion fails the <param name="defaultValue">default value</param> will be returned.
        /// </summary>
        public static T ConvertTo<T>(this string value, CultureInfo culture, T defaultValue)
        {
            return ConvertTo<T>(value, culture, defaultValue, false);
        }

		/// <summary>
        /// Converts the specified string value to its strong-typed counterpart. If the conversion fails 
        /// either an exception is raised or the default value will be returned.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="culture">The culture.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <param name="raiseException">if set to <c>true</c> [raise exception].</param>
        /// <returns></returns>
        private static T ConvertTo<T>(string value, CultureInfo culture, T defaultValue, bool raiseException)
        {
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
            try
            {
                //nasty but needed because the BCL is not turning on the right NumberStyle flags
                if (converter is BaseNumberConverter)
                {
                    return (T)HandleThousandsSeparatorIssue<T>(converter, value, culture);
                }
                else
                {
                    return (T)converter.ConvertFromString(null, culture, value);
                }
            }
            catch (Exception ex)
            {
                if (raiseException)
                    throw ex;

                return defaultValue;
            }
        }

		/// <remarks>
        /// Thousands Separator issue 
        /// http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/c980b925-6df5-428d-bf87-7ff83db4504c/
        /// </remarks>
        private static object HandleThousandsSeparatorIssue<T>(TypeConverter converter, string value, CultureInfo culture)
        {
            NumberStyles styles = NumberStyles.Number;
            IFormatProvider format = culture.NumberFormat;

            if (typeof(T).Equals(typeof(double)))
            {
                return double.Parse(value, styles, format);
            }
            if (typeof(T).Equals(typeof(Single)))
            {
                return Single.Parse(value, styles, format);
            }
            if (typeof(T).Equals(typeof(decimal)))
            {
                return decimal.Parse(value, styles, format);
            }
            if (typeof(T).Equals(typeof(int)))
            {
                return int.Parse(value, styles ^ NumberStyles.AllowDecimalPoint, format);
            }

            return (T)converter.ConvertFromString(null, culture, value);
        }

		public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
		#endregion
    }

    public static class DateTimeExtensions
    {
		#region Static Methods (2)
		public static DateTime MaxValue(this DateTime sqlDateTime)
        {
            return new DateTime(2079, 06, 06, 23, 59, 00);
        }

		public static DateTime MinValue(this DateTime sqlDateTime)
        {
            return new DateTime(1900, 01, 01, 00, 00, 00);
        }
		#endregion
    }


}